﻿using GenericityDispatch.DispatchAttribute;
using GenericityDispatch.Events;
using Miao.Utility.Core;
using Newtonsoft.Json;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Metadata;
using System.Text;
using System.Threading.Channels;
using System.Threading.Tasks;

namespace GenericityDispatch
{
    /// <summary>
    /// 基础实现
    /// </summary>
    public class BaseBus
    {
        private static BaseBus Instance = null;
        private static readonly object obj = new object();
        /// <summary>
        /// 使用单例，防止对象多次创建初始化
        /// </summary>
        /// <returns></returns>
        public static BaseBus GetInstance()
        {
            //双重锁定
            if (Instance == null)//只有为null需要实例化处理时才进行加锁，提高性能避免不必要的等待
            {
                lock (obj)
                {
                    if (Instance == null)//避免其他线程等待锁释放期间有线程已经实例化，从而造成多个实例
                        Instance = new BaseBus();
                }
            }
            return Instance;
        }

        /// <summary>
        /// 防止使用new创建对象
        /// </summary>
        private BaseBus()
        {
            BaseBusInit();
        }

        /// <summary>
        /// 节点对应实现字典
        /// 使用线程安全字典存放，防止多线程问题
        /// </summary>
        public static ConcurrentDictionary<string, ReflectionClassInfo> RealizationDictionary = new ConcurrentDictionary<string, ReflectionClassInfo>();


        /// <summary>
        /// 参数对应字典
        /// 使用线程安全字典存放，防止多线程问题
        /// </summary>
        public static ConcurrentDictionary<string, List<ParameterClassInfo>> ParameterDictionary = new ConcurrentDictionary<string, List<ParameterClassInfo>>();

        /// <summary>
        /// 初始化
        /// </summary>
        private void BaseBusInit()
        {
            System.Reflection.Assembly[] allAssembly = AppDomain.CurrentDomain.GetAssemblies();
            System.Reflection.Assembly.GetExecutingAssembly();
            List<Type> realizationTypes = new List<Type>();
            Assembly.GetAssembly(typeof(IEventHandler<>));
            foreach (Assembly assembly in allAssembly)
            {
                var types = assembly.GetTypes().Where(x => (x?.BaseType?.IsGenericType ?? false) && x.GetInterfaces().Count() > 0).ToList();
                realizationTypes.AddRange(types);
            }
            foreach (var realizationType in realizationTypes)
            {
                var genericArguments = realizationType.BaseType.GetGenericArguments();
                if (genericArguments == null || !genericArguments.Any())
                    continue;
                var attributions = realizationType.GetCustomAttributes(typeof(FlowNodeAttribute), false);
                if (attributions == null || attributions.Length == 0)
                    continue;
                var attribution = attributions[0] as FlowNodeAttribute;
                if (attribution == null || string.IsNullOrWhiteSpace(attribution.FlowNodeName))
                    continue;
                var flowNodeName = attribution.FlowNodeName;
                var index = attribution.Index;
                var reflectionClassInfo = ReflectionClassInfo.CreateInstance(realizationType, index);
                if (!RealizationDictionary.ContainsKey(flowNodeName))
                    RealizationDictionary.TryAdd(flowNodeName, reflectionClassInfo);
                var argFirst = reflectionClassInfo.GenericArguments.FirstOrDefault();
                if (argFirst != null)
                {
                    var parameterClassInfos = new List<ParameterClassInfo>()
                    {
                        new ParameterClassInfo()
                        {
                            FlowNodeName = flowNodeName,
                            ReflectionClassInfo = reflectionClassInfo
                        }
                    };
                    var argFirstName = argFirst.FullName;
                    if (ParameterDictionary.ContainsKey(argFirstName))
                    {
                        List<ParameterClassInfo> value = ParameterDictionary[argFirstName];
                        if (value == null)
                            continue;
                        var valueFirst = value.FirstOrDefault(x => x.FlowNodeName == flowNodeName);
                        if (valueFirst != null)
                            continue;
                        value.AddRange(parameterClassInfos);
                        ParameterDictionary[argFirstName] = value;
                    }
                    else
                        ParameterDictionary.TryAdd(argFirstName, parameterClassInfos);
                }
            }
        }



        /// <summary>
        /// 消息发布
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="msg"></param>
        public void Publish<T>(T msg) where T : Event
        {
            var flowNodeName = string.Empty;
            try
            {
                var argName = typeof(T).FullName;
                if (ParameterDictionary.ContainsKey(argName))
                {
                    List<ParameterClassInfo> value = ParameterDictionary[argName];
                    if (value == null || !value.Any()) return;
                    var parameters = value.OrderBy(x => x.ReflectionClassInfo.Index).ToList();
                    foreach (var parameter in parameters)
                    {
                        var type = new Type[] { typeof(T), parameter.ReflectionClassInfo.ClassType };
                        this.FastInvoke(type,
                                        x => x.ConsumerTo<T, IEventHandler<Event>>(msg, parameter.FlowNodeName),
                                        new object[] { msg, parameter.FlowNodeName });

                        StringBuilder stringBuilder = new StringBuilder();
                        stringBuilder.AppendLine($"*********调度中心数据************");
                        stringBuilder.AppendLine($"获取到节点{parameter.FlowNodeName}");
                        stringBuilder.AppendLine($"获取到节点请求参数{JsonConvert.SerializeObject(msg)}");
                        stringBuilder.AppendLine($"节点运行结束，状态正常");
                        stringBuilder.AppendLine($"*********调度中心数据************");
                        Console.WriteLine(stringBuilder);   
                    }
                }
                //TODO:此处可以获取节点运行的情况，获取对应节点是否执行完成
                //也可以根据节点自动更新节点组数组
            }
            catch (Exception e)
            {
                StringBuilder stringBuilder = new StringBuilder();
                stringBuilder.AppendLine($"*********调度中心数据************");
                stringBuilder.AppendLine($"获取到节点{flowNodeName}");
                stringBuilder.AppendLine($"获取到节点请求参数{JsonConvert.SerializeObject(msg)}");
                stringBuilder.AppendLine($"节点运行结束，节点运行异常");
                stringBuilder.AppendLine($"*********调度中心数据************");
                Console.WriteLine(stringBuilder);
                ///记录节点运行异常
                throw e;
            }
        }

        /// <summary>
        /// 处理
        /// </summary>
        /// <typeparam name="TEvent"></typeparam>
        /// <typeparam name="TRealization"></typeparam>
        /// <param name="_content"></param>
        public void ConsumerTo<TEvent, TRealization>(TEvent @event, string flowNodeName)
         where TRealization : IEventHandler<TEvent>
         where TEvent : Event
        {
            TRealization realizationInstance = (TRealization)RealizationDictionary[flowNodeName].ClassObj;
            realizationInstance.Handle(@event);
        }
    }
}
